#ifndef __GXCP_H__
#define __GXCP_H__



#include "qe_def.h"
#include "qe_pack.h"
#include "qe_buffer.h"



/*
 * Error codes 
 */
typedef enum {
    GXCP_SUCCESS            = 0,
    GXCP_NOT_IMPLEMENTED    = 1,
    GXCP_INVALID_PARAMETER  = 2,
    GXCP_INVALID_ADDRESS    = 3,
    GXCP_INVALID_LENGTH     = 4,
    GXCP_INVALID_HEADER     = 5,

    GXCP_WRITE_PROTECT      = 16,
    GXCP_BAD_ALIGNMENT      = 17,
    GXCP_ACCESS_DENIED      = 18,
    GXCP_BUSY               = 19,
    GXCP_MSG_TIMEOUT        = 20,

    GXCP_WRONG_CONFIG       = 32,

    GXCP_ERROR              = 0xFFFF,
} gxcp_ret;

typedef struct
{
    qe_u32 protocol_version;
    char manufacturer_name[64];
    char model_name[64];
    char family_name[64];
    char device_version[64];
    char manufacturer_info[64];
    char serial_number[64];
    char user_defined_name[64];
    qe_u64 device_capability;
    qe_u32 max_dev_response_time;
    qe_u64 manifest_table_address;
    qe_u64 sbrm_address;
    qe_u64 device_configuration;
    qe_u32 heartbeat_timeout;
    qe_u32 message_channel_id;
    qe_u64 timestamp;
    qe_u32 timestamp_latch;
    qe_u64 timestamp_increment;
    qe_u32 access_privilege;
    qe_u32 reserved;
    qe_u32 impl_endianess;
} qe_packed gxcp_bootstrap_regs;

typedef struct
{
    gxcp_ret (*readmem)(qe_u32 addr, qe_u8 *data, qe_size size, void *user);
    gxcp_ret (*writemem)(qe_u32 addr, qe_u8 *data, qe_size size, void *user);
    gxcp_ret (*set_user_defined_name)(char *name);
    gxcp_ret (*set_configure)(qe_u32 cfg);
    gxcp_ret (*set_heartbeat_timeout)(qe_u32 timeout);
    gxcp_ret (*event)(void);

    /* File operation */
    gxcp_ret (*file_size)(const char *name, qe_size *size);
    void *(*file_open)(const char *name, int mode);
    void (*file_close)(void *handle);
    gxcp_ret (*file_read)(void *handle, void *buf, qe_size size, qe_u32 *result);
    gxcp_ret (*file_write)(void *handle, void *buf, qe_size size, qe_u32 *result);
    gxcp_ret (*file_delete)(const char *name);
} gxcp_callback;

typedef struct
{
    qe_int (*read)(qe_u8 *data, qe_size size, void *user);
    qe_int (*write)(qe_u8 *data, qe_size size, void *user);
} gxcp_io;

typedef struct
{
    qe_u32 filelist_address;
    qe_u32 filelist_size;
    qe_u32 status;
    qe_u32 result;
    char filename[128];
    int opt;
    int open_mode;
    int offset;
    int length;
    void *handle;
    qe_gbuf *buf;
} gxcp_file_operation;

typedef struct
{
    gxcp_io io;
    gxcp_callback cb;
    void *user;
    qe_gbuf *txbuf;
    qe_gbuf *rxbuf;
    qe_u16 request_id;
    qe_u16 channel_id;
    gxcp_bootstrap_regs bsr;
    gxcp_file_operation file_op;
} gxcp_ctx;

typedef struct
{
    qe_u32 preamble;
    qe_u16 channel_id;
    qe_u16 length;
    qe_u8 fcs;
    qe_u8 data[0];
} qe_packed gxcp_prefix;

#define GXCP_PREFIX_SIZE        sizeof(gxcp_prefix)

typedef struct
{
    qe_u16 channel_id;
    qe_pack_buffer payload;
} gcmp_unpacked;

typedef struct
{
    qe_u16 flags;
    qe_u16 command;
    qe_u16 request_id;
    qe_u8 data[0];
} qe_packed gxcp_ccd_cmd;

typedef struct
{
    qe_u32 address;
    qe_u16 length;
} qe_packed gxcp_scd_readmem;

typedef struct
{
    qe_u32 address;
    qe_u16 length;
    qe_u8 data[0];
} qe_packed gxcp_scd_writemem;

typedef struct
{
    qe_u16 channel_id;
    qe_u16 flags;
    qe_u16 command_id;
    qe_u16 request_id;
    union {
        struct {
            qe_u32 address;
            qe_u16 length;
        } readmem;
        struct {
            qe_u32 address;
            qe_u16 length;
            qe_u8 *data;
        } writemem;
    };
} gxcp_request;

qe_ret
gxcp_init(gxcp_ctx *g, qe_size bufsz, void *user);

void
gxcp_set_io(gxcp_ctx *g, gxcp_io *io);

void
gxcp_set_callback(gxcp_ctx *g, gxcp_callback *cb);

void
gxcp_set_bootstrap(gxcp_ctx *g, gxcp_bootstrap_regs *bsr);

void 
gxcp_set_channel_id(gxcp_ctx *g, qe_u16 channel_id);

qe_ret
gxcp_rx_handle(gxcp_ctx *g, qe_u8 *data, qe_size size);

void 
gxcp_set_filelist(gxcp_ctx *g, qe_u32 address);



#endif /* __GXCP_H__ */